package cn.sylinx.hbatis.ext.parse;

import java.util.ArrayList;
import java.util.List;

import cn.sylinx.hbatis.ext.function.FunctionParser;
import cn.sylinx.hbatis.ext.ifblock.IfEndBlockParser;
import cn.sylinx.hbatis.ext.ifblock.IfEndBlockParserImpl;
import cn.sylinx.hbatis.ext.ifblock.IfEndMatcher;
import cn.sylinx.hbatis.ext.ifblock.IfEndMatcherImpl;
import cn.sylinx.hbatis.kit.Tuple;
import cn.sylinx.hbatis.log.GLog;

/**
 * 参数占位符
 * 
 * @author han
 *
 */
public class GenericTokenParser {

	// 静态参数解析
	private final static String TOKEN_BEGIN = "#{";
	private final static String TOKEN_END = "}";

	// 外部sql解析
	private final static String TOKEN_DY_BEGIN = "${";
	private final static String TOKEN_DY_END = "}";

	// 判断符号
	private final static String TOKEN_IF_BEGIN = "#IF";

	private TokenHandler handler;

	public GenericTokenParser(TokenHandler handler) {
		this.handler = handler;
	}

	/**
	 * format
	 * 
	 * @param preSt
	 * @return
	 */
	protected String formatPreStatement(String preSt) {

		return preSt.replaceAll("\r", " ").replaceAll("\n", " ").replaceAll("\t", " ");
	}

	/**
	 * 返回sql 和 sql参数, Tuple[0]:sql Tuple[1]:参数
	 * 
	 * @param st
	 * @return
	 */
	public Tuple parse(String preSt) {

		// 1、sql排版
		String preSt1 = formatPreStatement(preSt);

		// 2、解析出动态sql
		String preSt2 = parseDynamicSql(preSt1);

		// 3、解析外部加入动态sql
		String preSt3 = parseDynamicPartSql(preSt2);

		// 4、解析函数
		String st = parseFunctions(preSt3);

		// 5、以下解析参数
		List<Object> ps = new ArrayList<Object>();
		StringBuilder sb = new StringBuilder();
		getNextPart(st, sb, ps);
		String rst = sb.toString();
		sb.setLength(0);
		Object[] params = new Object[ps.size()];
		ps.toArray(params);

		GLog.debug("orgin sql: " + rst);
		GLog.debug("orgin parameters:" + ps);

		return Tuple.apply(rst, params);

	}

	/**
	 * 解析函数
	 * 
	 * @param st
	 * @return
	 */
	protected String parseFunctions(String st) {
		return new FunctionParser(handler).parse(st);
	}

	protected String parseDynamicSql(String st) {

		StringBuilder sb = new StringBuilder();
		parseDynamicSqlNext(st, sb);
		return sb.toString();
	}

	protected String parseDynamicPartSql(String st) {
		StringBuilder sb = new StringBuilder();
		parseDynamicPartSqlNext(st, sb);
		return sb.toString();
	}

	private void parseDynamicPartSqlNext(String st, StringBuilder sb) {

		if (st == null) {
			throw new RuntimeException("statment is null");
		}

		int is = st.indexOf(TOKEN_DY_BEGIN);
		if (is == -1) {
			sb.append(st);
			return;
		}

		String tmp = st.substring(is);
		int is1 = tmp.indexOf(TOKEN_DY_END);
		int ie = is1 + is;

		if (is1 == -1) {
			throw new RuntimeException("illegal statement");
		}

		String split = st.substring(is + TOKEN_DY_BEGIN.length(), ie);
		// String dynamicSql = (String) handler.hand(split);
		String dynamicSql = null;
		Object dynamicObject = handler.hand(split);
		if (dynamicObject != null) {
			dynamicSql = dynamicObject.toString();
		}
		String before = st.substring(0, is) + (dynamicSql == null ? "" : dynamicSql);
		sb.append(before);

		String after = st.substring(ie + TOKEN_DY_END.length());
		parseDynamicPartSqlNext(after, sb);
	}

	private void parseDynamicSqlNext(String st, StringBuilder sb) {

		if (st == null) {
			throw new RuntimeException("statment is null");
		}

		int is = st.indexOf(TOKEN_IF_BEGIN);
		if (is == -1) {

			sb.append(st.trim()).append(" ");
			return;
		}

		String left = st.substring(is);
		String split = findMatchIfEnd(left);
		int ie = is + split.length();

		// 条件是否以#IF[开头
		boolean bl = split.startsWith("#IF[");

		if (!bl) {
			throw new RuntimeException("illegal condition statement");
		}

		// 将前面部分拼接
		String before = st.substring(0, is);
		sb.append(before.trim()).append(" ");

		IfEndBlockParser block = new IfEndBlockParserImpl(handler);
		sb.append(block.parse(split));

		String after = st.substring(ie);
		// 解析剩余部分
		parseDynamicSqlNext(after, sb);

	}

	private String findMatchIfEnd(String left) {

		IfEndMatcher matcher = new IfEndMatcherImpl();
		return matcher.findMatchIfEnd(left);
	}

	private void getNextPart(String st, StringBuilder sb, List<Object> ps) {

		if (st == null) {
			throw new RuntimeException("statment is null");
		}

		int is = st.indexOf(TOKEN_BEGIN);
		if (is == -1) {
			sb.append(st);
			return;
		}

		String tmp = st.substring(is);
		int is1 = tmp.indexOf(TOKEN_END);
		int ie = is1 + is;
		// int ie = st.indexOf(TOKEN_END);
		if (is1 == -1) {
			throw new RuntimeException("illegal statement");
		}

		String split = st.substring(is + TOKEN_BEGIN.length(), ie);
		ps.add(handler.hand(split));

		String before = st.substring(0, is) + "?";
		sb.append(before);
		String after = st.substring(ie + TOKEN_END.length());

		getNextPart(after, sb, ps);
	}
}
